#include "udp.h"
#include "uv.h"
#include<stdio.h>

static uv_udp_t client;

static sockaddr_in addr;

static sockaddr_in serveraddr;

#define TEST_PORT 9123

//---------------------------------------------------------------------------------

#define ASSERT(expr)                                      \
 do {                                                     \
  if (!(expr)) {                                          \
    fprintf(stderr,                                       \
            "Assertion failed in %s on line %d: %s\n",    \
            __FILE__,                                     \
            __LINE__,                                     \
            #expr);                                       \
    abort();                                              \
  }                                                       \
 } while (0)

static void close_walk_cb(uv_handle_t* handle, void* arg) {
  if (!uv_is_closing(handle))
    uv_close(handle, NULL);
}

static void alloc_cb(uv_handle_t* handle,size_t suggested_size,uv_buf_t* buf) {
  static char slab[65536];
  ASSERT(suggested_size <= sizeof(slab));
  buf->base = slab;
  buf->len = sizeof(slab);
}

//-----------------------------------------------------------------------------------

int udp_init()
{

	uv_udp_init(uv_default_loop(),&client);

	ASSERT(0 == uv_ip4_addr("0.0.0.0", TEST_PORT, &addr));

	uv_udp_bind(&client,(const sockaddr *)&addr,0);

}

void udp_open(const char *server_addr, int server_port)
{
	ASSERT(0 == uv_ip4_addr(server_addr, server_port, &serveraddr));
}

static void cl_send_cb(uv_udp_send_t* req, int status) {
 
  ASSERT(req != NULL);
  ASSERT(status == 0);
  
}
int udp_send(char *data, size_t size)
{
	int r;
	uv_udp_send_t req;
	uv_buf_t buf;

	buf = uv_buf_init(data, size);

	r = uv_udp_send(&req,&client,&buf,1,(const struct sockaddr*) &serveraddr,cl_send_cb);

  return r;
}
static void cl_recv_cb(uv_udp_t* handle,ssize_t nread,const uv_buf_t* rcvbuf,const struct sockaddr* addr,unsigned flags) {
  
  int r;

  if (nread < 0) {
    ASSERT(0 && "unexpected error");
  }

  if (nread == 0) {
    ASSERT(addr == NULL);
    return;
  }
  
  ASSERT(flags == 0);
  ASSERT(addr != NULL);

  printf("cl recv from %s:\n %s\n",addr->sa_data,rcvbuf->base);


}
int udp_begin_recv()
{
	int r;

	r = uv_udp_recv_start(&client, alloc_cb, cl_recv_cb);
	
	return r;
}


void udp_close()
{
	ASSERT(0 == uv_ip4_addr("127.0.0.1", TEST_PORT, &serveraddr));
}

void udp_quit()
{
	uv_walk(uv_default_loop(),close_walk_cb,0);
    uv_loop_close(uv_default_loop());  
}


